package com.ld.admin.shiro.filter;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;

import com.ld.admin.model.system.SystemUser;
import com.ld.admin.service.user.IUserService;
import com.ld.admin.service.user.UserService;
import com.ld.admin.shiro.ShiroUtils;
import com.ld.common.util.LoginCookieUtil;
import com.ld.shieldsb.common.composition.util.web.Global;
import com.ld.shieldsb.common.core.model.PropertiesModel;
import com.ld.shieldsb.common.core.model.Result;
import com.ld.shieldsb.common.core.util.SpringContextHolder;
import com.ld.shieldsb.common.core.util.StringUtils;
import com.ld.shieldsb.common.web.util.Web;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ShiroLoginFilter extends FormAuthenticationFilter {
    protected String adminPath = Global.CONFIG.getString(Web.Property.CONFIG_ADMINPATH);
    protected String frontPath = Global.CONFIG.getString(Web.Property.CONFIG_FRONTPATH);
    // 使用名称获取，不建议使用类型，名称可以在config配置类中覆盖
    protected IUserService userService = null;

    protected IUserService getUserService() {
        if (userService == null) {
            userService = SpringContextHolder.getBeanByClassName(UserService.class);
        }
        return userService;
    }

    // 未登录的处理参数
    public static final String NOLOG_LOGINTYPE = "logintype"; //
    public static final String NOLOG_LOGINTYPE_DIALOG = "dialog"; // ,dialog（弹出框）
    public static final String NOLOG_LOGINTYPE_REDIRECT = "redirect"; // redirect(重定向)
    public static final String NOLOG_LOGINTYPE_RELOAD = "reload"; // reload（当前页面刷新）
    public static final String NOLOG_LOGINURL = "loginurl"; // 跳转url

    /**
     * 在访问controller前判断是否登录，返回json，不进行重定向。
     * 
     * @param request
     * @param response
     * @return true-继续往下执行，false-该filter过滤器已经处理，不继续执行其他过滤器
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest req, ServletResponse resp) throws IOException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        try {
            if (loginByCookie(request, response)) { // 通过cookie登录,true表示验证通过
                return true;
            }
            if (dealNoLogin(request, response)) { // 未登录处理
                return true;
            }
        } catch (ServletException | IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 处理未登录的情况
     * 
     * @Title dealNoLogin
     * @author 吕凯
     * @date 2019年8月26日 下午2:08:35
     * @param request
     * @param response
     * @param uri
     * @return
     * @throws ServletException
     * @throws IOException
     *             boolean
     */
    protected boolean dealNoLogin(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String loginurl = PropertiesModel.CONFIG.getString("admin.login.url"); // 后台ajax登录地址，不带项目名及后台名，不拦截

        String uri = Web.Request.getRelativeURI(request); // 相对uri
        if (uri.endsWith(loginurl)) { // 登录页不拦截
            return true;
        }
        if (ShiroUtils.isAjax(request)) { // ajax请求
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put(NOLOG_LOGINTYPE, NOLOG_LOGINTYPE_DIALOG); // 需要登录：支持 redirect(重定向),reload（当前页面刷新）,dialog（弹出框）
            ServletContext context = request.getServletContext();
            String ctxPath = context.getContextPath();
            if (StringUtils.isNotBlank(loginurl)) {
                dataMap.put(NOLOG_LOGINURL, ctxPath + adminPath + loginurl); // 登录url
            } else {
                if (!NOLOG_LOGINTYPE_RELOAD.equals(dataMap.get(NOLOG_LOGINTYPE))) { // 未定义loginurl的情况应该是刷新，如果类型不是刷新则发出警告
                    log.warn("后台登录地址未配置：admin.login.url，调用reload方法");
                    dataMap.put(NOLOG_LOGINTYPE, NOLOG_LOGINTYPE_RELOAD);
                }
            }
            Web.Response.responseJson(response, "登录超时！", dataMap, false);// 返回登录json
        } else { // 普通页面处理
            request.getRequestDispatcher("/" + adminPath + "/toLogin").forward(request, response); // 跳转
        }
        return false;
    }

    /**
     * 通过cookie登录的处理，登录成功返回true，登录失败返回false
     * 
     * @Title loginByCookie
     * @author 吕凯
     * @date 2019年8月26日 下午2:08:49
     * @param request
     * @param response
     * @return boolean
     */
    protected boolean loginByCookie(HttpServletRequest request, HttpServletResponse response) {
        SystemUser systemUser = LoginCookieUtil.loginCookie2User(request, response); // 判断cookie用户是否存在
        if (systemUser != null) { // cookie存在
            Result result = getUserService().loginNoCheckVerifyCode(request, systemUser.getLoginCode(), systemUser.getPassword());
            if (result.getSuccess()) {
                return true;
            }
        }
        return false;
    }

}